class Mvvm{
    constructor(options) {
        this.$el = options.el;
        this.$data = options.data;
        if(this.$el){
            //1.数据劫持
            new Observer(options.data);
            //2.模板编译
            new Compile(options.data,options.el);
        }
    } 
}

class Dep{
    constructor(){
        this.watchers = [];
    }

    add(watcher){
        this.watchers.push(watcher);
    }

    notify(){
        this.watchers.forEach(watcher => {
            watcher.update();
        })
    }
}

//监听器
class Watcher{
    constructor(expr,data,cb){
        this.data = data;
        this.cb = cb;
        this.expr = expr;
        this.oldVal = this.getVal();
    }

    getVal(){
        Dep.target = this;
        this.oldVal =  compileUtil.getVal(this.expr,this.data);
        Dep.target = null;
    }

    update(){
        let newVal = compileUtil.getVal(this.expr,this.data);
        if(newVal !== this.oldVal){
            this.cb(newVal);
        }
    }

}

// vm.$watch(,key,cb)

class Compile{
    constructor(data,el){
        //判断el是字符串还是dom节点
        this.el = this.isElementNode(el) ? el : document.querySelector(el);
        this.data = data;
        //1.创建代码片段,把所有的子节点放到代码片段内
        let fragment = this.nodeToFragment(this.el);

        //编译
        this.compile(fragment,data);
        
        //编译的结果放到页面上
        this.el.appendChild(fragment);
    }

    //判断是否dom节点
    isElementNode(el){
        return el.nodeType === 1
    }

    nodeToFragment(el){
        let fragment = document.createDocumentFragment();
        let childNodes = [...el.childNodes];
        for(let i = 0;i<childNodes.length;i++){
            fragment.appendChild(childNodes[i])
        }
        return fragment
    }

    //判断是否是指令
    isDirective(attr){
        return attr.startsWith('v-')
    }

    //编译节点
    compileElement(node){
        let attributes = node.attributes;
        [...attributes].forEach(attr => {
            let {name,value:expr} = attr;
            if(this.isDirective(name)){
                let [,directive] = name.split('-');
                //指令
                compileUtil[directive](node,expr,this.data)
            }
        })
    }

    //编译文本节点
    compileText(nodeText){
        let content = nodeText.textContent;
        console.log(content);
        if(/\{\{(.+?)\}\}/.test(content)){
            compileUtil.content(nodeText,this.data);
        }
    }

    //编译
    compile(node){
        let childNodes = [...node.childNodes];

        for(let i = 0;i<childNodes.length;i++){
            //判断是元素还是文本节点
            if(this.isElementNode(childNodes[i])){
                this.compile(childNodes[i])
                //编译元素节点
                this.compileElement(childNodes[i])
            }else{
                //编译文本节点
                this.compileText(childNodes[i]);
            }
        }
    }
}

const compileUtil = {

    getVal(expr,data){
        //[address,city]
        let value = expr.split('.').reduce((prev,cur) => {
            return prev[cur]
        },data);
        return value;
    },

    setVal(data,expr,value){
        expr.split('.').reduce((pre,cur,index,arr) => {
            if(index === arr.length-1){
                pre[cur] = value;
            }
            return pre[cur]
        },data)
    },

    model(node,expr,data){
        console.log(expr,data);
        let value = this.getVal(expr,data);
        new Watcher(expr,data,(newVal) => {
            this.updater.model(node,newVal);
        })
        // console.log("value",value)
        this.updater.model(node,value);
        node.addEventListener('input',(e) => {
            this.setVal(data,expr,e.target.value);
        })
    },

    content(node,data){
        let content = node.textContent;
        console.log(node.textContent);
        let text = content.replace(/\{\{(.+?)\}\}/g,(...argv)=>{
            let expr = argv[1];
            new Watcher(argv[1],data,(newValue) => {
                this.updater.content(node,newValue)
            })
            let value = this.getVal(expr,data);

            return value
        })

        this.updater.content(node,text);
    },

    updater:{
        model(node,value){
            node.value = value;
        },
        content(node,value){
            node.textContent = value;
        }
    }
}

//数据劫持

class Observer{
    constructor(data){
        this.observer(data);
    }

    observer(data){
        if(typeof data === 'object'){
            for(let key in data){
                this.observerData(data,key,data[key])
            }
        }
    }

    observerData(data,key,value){
        let dep = new Dep();
        this.observer(value);
        Object.defineProperty(data,key,{
            set(newVal){
                console.log("设置值",newVal)
                if(value !== newVal){
                    value = newVal;
                    dep.notify();
                }
            },
            get(){
                Dep.target && dep.add(Dep.target);
                console.log("获取值")
                return value
            }
        })
    }
}